/* $Id: MergeSpecial.cs,v 1.3 2005/01/12 06:36:30 larsbm Exp $
 * Copyright (c) 2004 Engine EAR GmbH & Co. KG
 * Developed by: Lars Behrmann, lb@engine.de
 */

using System;
using System.Data;

namespace SQLToNeo.Model
{
	/// <summary>
	/// MergeSpecial - merge the current local and the current dataset based on the 
	/// current db
	/// </summary>
	public class MergeSpecial
	{
		private DataSet _current;
		private DataSet _currentDB;
		private bool _generateJavaName;

		public MergeSpecial(bool generateJavaName)
		{
			_generateJavaName = generateJavaName;
		}

		public MergeSpecial()
		{
		}

		public DataSet Merge(DataSet current, DataSet currentDB)
		{
			_current = current;
			_currentDB = currentDB;
			Delete();
			Add();

			return _current;
		}

		public bool GenerateJavaName
		{
			get
			{
				return _generateJavaName;
			}
			set
			{
				_generateJavaName = value;
			}
		}

		private void Delete()
		{
			foreach(DataRow dr in _current.Tables["table"].Rows)
			{
				string s = dr["name"].ToString();
				DataRow[] drs = _currentDB.Tables["table"].Select("name = '"+s+"'");
				if(drs.Length == 0)
				{
					foreach(DataRow dr1 in dr.GetChildRows("cols"))
						dr1.Delete();
					foreach(DataRow dr2 in dr.GetChildRows("foreignkeys"))
						dr2.Delete();
					foreach(DataRow dr3 in dr.GetChildRows("iforeignkeys"))
						dr3.Delete();
					dr.Delete();
				}
			}
			_current.AcceptChanges();
			foreach(DataRow dr in _current.Tables["column"].Rows)
			{
				int id = GetTableId(_currentDB, dr.GetParentRow("cols")["name"].ToString());
				DataRow[] drs = _currentDB.Tables["column"].Select("name = '"+dr["name"].ToString()+"' and tableid = '"+id+"'");
				if(drs.Length == 0)
				{
					dr.Delete();
				}
				//Update the row with changes that maybe made by the user on server
				else
				{
					//Because of the sql restrictions there could only be own row due to this selectstatement above
					dr["type"] = drs[0]["type"];
					dr["size"] = drs[0]["size"];
					dr["required"] = drs[0]["required"];
					dr["primaryKey"] = drs[0]["primaryKey"];
					dr["identity"] = drs[0]["identity"];
				}
			}
			_current.AcceptChanges();
			
			string[] rels = new string[2] {"foreignkey","iforeignkey"};
			foreach(string rel in rels)
				foreach(DataRow dr in _current.Tables[rel].Rows)
				{
					int id = GetTableId(_currentDB, dr.GetParentRow(rel+"s")["name"].ToString());
					string select = "tableid = '"+id+"' and foreigntable = '"+dr["foreigntable"].ToString()+"'";
					select += " and local = '"+dr["local"].ToString()+"' and foreign = '"+dr["foreign"].ToString()+"'";
					DataRow[] drs = _currentDB.Tables[rel].Select(select);
					if(drs.Length == 0)
					{
						dr.Delete();
					}
					else 
					{
						//Update maybe there are changes made by the user on the server
						//the only things that could be changed
						dr["onDelete"] = drs[0]["onDelete"];
						dr["onUpdate"] = drs[0]["onUpdate"];
					}
				}
			_current.AcceptChanges();
		}

		private string ToLeadingCaps( string name )
		{
			char[] chars = name.ToCharArray();
			chars[0] = Char.ToUpper( chars[0] );
			return new string( chars );
		}
	
		private string ToCamelCase(string name)
		{
			string[] segs = name.Split('_');
			if (segs.Length > 1)
			{
				string tmp = "";
				foreach (string seg in segs)
				{
					tmp += ToLeadingCaps( seg );
				}
				return tmp;
			}
			else
			{
				return ToLeadingCaps( name );
			}
		}

		private string StripTrailingS(string name)
		{
			if (name.EndsWith("S") || name.EndsWith("s"))
			{
				return name.Substring(0, name.Length - 1);
			}
			else
			{
				return name;
			}
		}

		private void Add()
		{			
			foreach(DataRow dr in _currentDB.Tables["table"].Rows)
			{
				string s = dr["name"].ToString();
				if (_generateJavaName)
					dr["javaName"] = StripTrailingS(ToCamelCase(s));
				DataRow[] drs = _current.Tables["table"].Select("name = '"+s+"'");
				if(drs.Length == 0)
				{
					_current.Tables["table"].ImportRow(dr);
				}
			}
			_current.AcceptChanges();

			foreach(DataRow dr in _currentDB.Tables["column"].Rows)
			{
				int id = GetTableId(_current, dr.GetParentRow("cols")["name"].ToString());
				DataRow[] drs = _current.Tables["column"].Select("name = '"+dr["name"].ToString()+"' and tableid = '"+id+"'");
				if(drs.Length == 0)
				{
					
					try
					{
						DataRow d = _current.Tables["column"].NewRow();
						d["tableid"] = id;
						d["name"] = dr["name"];
						if (_generateJavaName)
							d["javaName"] = ToCamelCase(dr["name"].ToString());
						d["size"] = dr["size"];
						d["required"] = dr["required"];
						d["type"] = dr["type"];
						d["primaryKey"] = dr["primaryKey"];
						d["identity"] = dr["identity"];
						_current.Tables["column"].Rows.Add(d);
					}
					catch(Exception ex)
					{
						System.Windows.Forms.MessageBox.Show(ex.Message);
					}
				}
			}
			_current.AcceptChanges();
			
			string[] rels = new string[2] {"foreignkey","iforeignkey"};
			foreach(string rel in rels)
				foreach(DataRow dr in _currentDB.Tables[rel].Rows)
				{
					int id = GetTableId(_current, dr.GetParentRow(rel+"s")["name"].ToString());
					string select = "tableid = '"+id+"' and foreigntable = '"+dr["foreigntable"].ToString()+"'";
					select += " and local = '"+dr["local"].ToString()+"' and foreign = '"+dr["foreign"].ToString()+"'";
					DataRow[] drs = _current.Tables[rel].Select(select);
					if(drs.Length == 0)
					{						
						try
						{
							DataRow d = _current.Tables[rel].NewRow();
							d["tableid"] = id;
							d["foreigntable"] = dr["foreigntable"];
							d["local"] = dr["local"];
							d["foreign"] = dr["foreign"];
							d["onDelete"] = dr["onDelete"];
							d["onUpdate"] = dr["onUpdate"];
							_current.Tables[rel].Rows.Add(d);
						}
						catch(Exception ex)
						{
							System.Windows.Forms.MessageBox.Show(ex.Message);
						}
					}
				}
			_current.AcceptChanges();
		}

		//Get the id from the current db state table table
		private int GetTableId(DataSet ds,string javatablename)
		{
			DataRow[] dr = ds.Tables["table"].Select("name = '"+javatablename+"'");
			if(dr.Length == 1)
				return Convert.ToInt32(dr[0]["id"].ToString());
			return -1;
		}
	}
}

/*
 * $Log: MergeSpecial.cs,v $
 * Revision 1.3  2005/01/12 06:36:30  larsbm
 * - Bugfixing: javaName and name were permuted
 *
 * Revision 1.2  2004/10/26 13:23:45  larsbm
 * - Fixed bugs in tablebuilder
 * - Working on the forms
 * - Finishing MergeSpecial
 * - Make app run with mergespecial
 * - start converter for sqldatatypes
 *
 * Revision 1.1  2004/10/25 13:47:16  larsbm
 * - Add new classes MergeSpecial and MergSpecialTest
 * - Merging the current local model with the current db schema on the server
 *
 */